CodeDeployのApplicationStopイベントフックはどう実行される?
AWSのPULL型デプロイサービスCodeDeployはデプロイの各ライフサイクルイベントに処理をフックすることができます。
デプロイは
- アプリケーションの停止
- アプリケーションファイルのダウンロード
- アプリケーションファイルのインストール
- アプリケーションの起動
という順で実行され、 次のデプロイライフサイクル図において、オレンジ背景の箇所が実際にフック処理を割り込めるイベントです。
イベント名から各イベントで何をやっているか想像はつきますが、ApplicationStop
イベントだけは注意が必要なため、補足します。
ApplicationStop イベントフックはどう実行される?
ライフサイクルイベントのフローを見ればわかるように、ApplicationStop
イベントは DownloadBundle
イベントよりも前に存在します。
そのため、ApplicationStop
イベントでは前回正常にデプロイされたリビジョンの AppSpec
ファイルと ApplicationStop
スクリプトを元に実行されます。
新規にデプロイするファイル群で定義した ApplicationStop
処理は、次回デプロイ時の ApplicationStop
イベントまで実行されません。
デプロイするファイル群はStart
からEnd
までのデプロイのライフサイクルに対応するわけではなく、 DownloadBundle
からApplicationStop
までのアプリケーションのライフサイクルに対応します。
注意しましょう。
CodeDeploy FAQにあるデプロイのライフサイクルイベントの説明を転載します。
デプロイのライフサイクルイベント | 説明 |
ApplicationStop | デプロイの最初のライフサイクルイベントであり、リビジョンのダウンロード前から開始します。このデプロイのライフサイクルイベントに使用される AppSpec ファイルおよびスクリプトは前回正常にデプロイされたリビジョンのものです。
アプリケーションを正常に停止する、またはデプロイの準備として最近インストールしたパッケージを削除する場合は ApplicationStop のデプロイのライフサイクルイベントを使用します。 |
DownloadBundle | このデプロイのライフサイクルイベントでは、エージェントがインスタンスの一時的なロケーションに、リビジョンファイルをコピーします。このデプロイのライフサイクルイベントはエージェント用にリザーブされており、ユーザーのスクリプトの実行には使用できません。 |
BeforeInstall | BeforeInstall ライフサイクルイベントはファイルの暗号化や現在のバージョンのバックアップ作成など、インストール前のタスクに使用します。 |
Install | このデプロイのライフサイクルイベントでは、エージェントが一時的なロケーションからリビジョンファイルを最終的な送信先フォルダにコピーします。このデプロイのライフサイクルイベントはエージェント用にリザーブされており、ユーザーのスクリプトの実行には使用できません。 |
AfterInstall | AfterInstall デプロイライフサイクルイベントはアプリケーションの設定またはファイルの許可の変更に使用します。 |
ApplicationStart | 基本的に、このデプロイのライフサイクルイベントは ApplicationStop で停止したサービスを再起動するために使用します。 |
ValidateService | ValidateService は最後のデプロイのライフサイクルイベントであり、デプロイが正常に完了したことを検証します。 |
ApplicationStop処理が原因でデプロイが失敗する!
ApplicationStop
イベントのエラーが原因で新規デプロイが失敗する時はどうすればよいでしょうか?
前述のとおり、ApplicationStop
イベントではデプロイ済みファイルが利用されます。
以下の2通りの対応があります。
- ApplicationStop イベントの処理を書き換える
- ApplicationStop イベントが失敗しても無視する
順に見ていきましょう。
1. ApplicationStop イベントの処理を書き換える
力ずくでデプロイ済みのファイルを書き換えます。
前回デプロイしたファイル群のパスは、次のファイルで確認できます。
/opt/codedeploy-agent/deployment-root/deployment-instructions/DEPLOYMENT-GROUP-ID_last_successful_install
手元の環境で確認すると次の様になっていました。
$ cat /opt/codedeploy-agent/deployment-root/deployment-instructions/706529a7-bef8-4f84-9fd6-3ba8994687ad_last_successful_install /opt/codedeploy-agent/deployment-root/706529a7-bef8-4f84-9fd6-3ba8994687ad/d-DLK7M2IBE $ tree /opt/codedeploy-agent/deployment-root/706529a7-bef8-4f84-9fd6-3ba8994687ad/d-DLK7M2IBE /opt/codedeploy-agent/deployment-root/706529a7-bef8-4f84-9fd6-3ba8994687ad/d-DLK7M2IBE ├── bundle.tar ├── deployment-archive │ ├── appspec.yml │ └── scripts │ └── application_stop └── logs └── scripts.log 3 directories, 4 files
あとは該当ファイルを修正するだけです。
きめ細かな修正ができる一方で、サーバー台数がたくさんあると、このアプローチは厄介です。
2. ApplicationStop イベントが失敗しても無視する
デプロイ(aws deploy create-deployment
)時に--ignore-application-stop-failures
スイッチを渡し、ApplicationStop
イベントで失敗しても、処理を継続させます。
エラーの発生するApplicationStop
スクリプトをデプロイした上で、新規にデプロイを実行して実際の動作を確認します。
$ aws deploy create-deployment \ --ignore-application-stop-failures \ --application-name foo \ --deployment-config-name CodeDeployDefault.OneAtATime \ --deployment-group-name foo \ --description "zip" \ --s3-location bucket=YOUR-BUCKET,bundleType=zip,key=cd/03.zip { "deploymentId": "d-DLK7M2IBE" }
デプロイの詳細を確認します。
$ aws deploy get-deployment-instance --deployment-id d-DLK7M2IBE --instance-id i-876fc318 { "instanceSummary": { "instanceId": "arn:aws:ec2:ap-northeast-1:123456789012:instance/i-876fc318", "status": "Succeeded", "deploymentId": "d-DLK7M2IBE", "lastUpdatedAt": 1460204425.313, "lifecycleEvents": [ { "endTime": 1460204413.889, "status": "Failed", "diagnostics": { "errorCode": "ScriptFailed", "scriptName": "scripts/application_stop", "logTail": "LifecycleEvent - ApplicationStop\nScript - scripts/application_stop\n[stderr]/opt/codedeploy-agent/deployment-root/706529a7-bef8-4f84-9fd6-3ba8994687 ad/d-VAOLFRQBE/deployment-archive/scripts/application_stop: line 2: fail: command not found\n", "message": "Script at specified location: scripts/application_stop failed with exit code 127" }, "startTime": 1460204413.773, "lifecycleEventName": "ApplicationStop" }, ... { "endTime": 1460204420.446, "status": "Succeeded", "diagnostics": { "errorCode": "Success", "scriptName": "", "logTail": "", "message": "Succeeded" }, "startTime": 1460204420.324, "lifecycleEventName": "ApplicationStart" }, { "endTime": 1460204423.768, "status": "Succeeded", "diagnostics": { "errorCode": "Success", "scriptName": "", "logTail": "", "message": "Succeeded" }, "startTime": 1460204423.634, "lifecycleEventName": "ValidateService" } ] } }
lifecycleEvents
のApplicationStop
イベントはstatus
がFailed
ですが(エラー内容はlogTail から確認できます)、 後続のイベントはSucceeded
で成功し、 デプロイそのものもstatus
はSucceeded
と成功しています。
注意点としては
- マネージメントコンソールからデプロイする時は
--ignore-application-stop-failures
スイッチを指定できない ApplicationStop
処理をまるごとスキップするわけではない
といったことがあります。
まとめ
今回はAWS CodeDeployを使った人が一度はハマると思われるApplicationStop
イベントについて解説しました。
バンドルファイルが展開されるタイミングと各イベントで利用されるバンドルファイルをしっかり理解しましょう。